package XML与JSON;
/*
StAX(Stream API for XML)是一种针对XML的流式拉分析API。本文主要介绍使用StAX方式处理XML，文中所使用到的软件版本：Java 1.8.0_191。

1、StAX简介
   StAX通过提供一种基于事件迭代器(Iterator)的API让使用者去控制xml文档解析过程，遍历这个事件迭代器去处理每一个解析事件，解析事件可以看做是程序拉出来的，
   也就是程序促使解析器产生一个解析事件然后处理该事件，之后又促使解析器产生下一个解析事件，如此循环直到碰到文档结束符。

1.1、与SAX区别
SAX和STAX都是基于事件驱动的。
SAX是推模式------解析器控制xml文件解析，由解析器调用相应的事件方法。
STAX是拉模式-----客户端程序自己控制xml事件，主动调用相应的事件方法。

1.2、拉模式的优点
1.在拉模式中，事件是由分析应用程序生成的，因此把分析规则提供到客户端而不是分析器。
2.拉模式的代码更简单并且它比推模式使用更少的库。
3.拉模式客户端能同时读多个XML文档。
4.拉模式允许你过滤XML文档并且跳过分析事件。

2、StAX使用
2.1、XML文件: student.xml
*/
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.namespace.QName;
import javax.xml.stream.*;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.XMLEvent;
import java.util.ArrayList;
import java.util.List;

public class StaxCase {
    private static Logger logger = LoggerFactory.getLogger(StaxCase.class);

    /**
     * 基于光标的方式解析xml
     * @throws Exception
     */
    @Test
    public void parse() throws Exception {
   	 System.out.println("\nparse----------");
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(StaxCase.class.getResourceAsStream("student.xml"));
        //添加过滤器
        XMLStreamReader filterReader = factory.createFilteredReader(reader, new StreamFilter() {
            @Override
            public boolean accept(XMLStreamReader reader) {
                //处理开始节点    只处理三种类型节点节点：
                if (reader.isStartElement() || reader.isEndElement() || reader.isCharacters()) {
                    return true;
                }
                return false;
            }
        });

        List<Student> students = new ArrayList<>();
        Student student = null;
        String text = "";
        while (filterReader.hasNext()) {
            int type = filterReader.next();
            if (type == XMLStreamReader.START_ELEMENT) {
                if ("student".equals(reader.getName().getLocalPart())) {
                    student = new Student();
                    students.add(student);

                    student.setRollno(Integer.parseInt(reader.getAttributeValue("", "rollno")));
                    String age = reader.getAttributeValue("http://www.w3.org/TR/html4/school/", "age");
                    if (StringUtils.isNotBlank(age)) {
                        student.setAge(Integer.parseInt(age));
                    }
                }
            } else if (type == XMLStreamReader.END_ELEMENT) {
                logger.info(reader.getName().getLocalPart());
                if ("firstname".equals(reader.getName().getLocalPart())) {
                    student.setFirstname(text);
                } else if ("lastname".equals(reader.getName().getLocalPart())) {
                    student.setLastname(text);
                } else if ("nickname".equals(reader.getName().getLocalPart())) {
                    student.setNickname(text);
                } else if ("marks".equals(reader.getName().getLocalPart())) {
                    student.setMarks(text);
                }

            } else if (type == XMLStreamReader.CHARACTERS) {
                text = reader.getText();
            }
        }
        logger.info(students.toString());
    }

    /**
     * 基于迭代模型的方式解析xml
     * @throws Exception
     */
    @Test
    public void parse2() throws Exception {
   	 System.out.println("\nparse2----------");
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLEventReader reader = factory.createXMLEventReader(StaxCase.class.getResourceAsStream("student.xml"));
        //添加过滤器
        XMLEventReader filterReader = factory.createFilteredReader(reader, event -> {
            //处理开始节点
            if (event.isStartElement() || event.isEndElement() || event.isCharacters()) {
                return true;
            }
            return false;
        });

        List<Student> students = new ArrayList<>();
        Student student = null;
        String text = "";
        while (filterReader.hasNext()) {
            XMLEvent event = filterReader.nextEvent();
            //System.out.println("eeee--"+event.getLocation());;
            if (event.isStartElement()) {
                if ("student".equals(event.asStartElement().getName().getLocalPart())) {//.getLocalPart()返回当前事件的（本地）名称。
                    student = new Student();
                    students.add(student);
                    student.setRollno(Integer.parseInt(event.asStartElement().getAttributeByName(new QName("", "rollno")).getValue()));
                    Attribute ageAttribute = event.asStartElement().getAttributeByName(new QName("http://www.w3.org/TR/html4/school/", "age"));
                    if (ageAttribute != null) {
                        student.setAge(Integer.parseInt(ageAttribute.getValue()));
                    }
                }
            } else if (event.isEndElement()) {
                logger.info(event.asEndElement().getName().getLocalPart());
                if ("firstname".equals(event.asEndElement().getName().getLocalPart())) {
                    student.setFirstname(text);
                } else if ("lastname".equals(event.asEndElement().getName().getLocalPart())) {
                    student.setLastname(text);
                } else if ("nickname".equals(event.asEndElement().getName().getLocalPart())) {
                    student.setNickname(text);
                } else if ("marks".equals(event.asEndElement().getName().getLocalPart())) {
                    student.setMarks(text);
                }
            } else if (event.isCharacters()) {
                text = event.asCharacters().getData();
            }
        }
        logger.info(students.toString());
    }
 
    @Test
    public void parse3() throws Exception {
   	 System.out.println("\nparse3----------");
   	 XMLInputFactory factory = XMLInputFactory.newInstance();
       XMLStreamReader reader = factory.createXMLStreamReader(StaxCase.class.getResourceAsStream("student.xml"));

       System.out.println(reader.getVersion());
       System.out.println(reader.isStandalone());
       System.out.println(reader.standaloneSet());
       System.out.println(reader.getEncoding());
       System.out.println(reader.getCharacterEncodingScheme());

       //parseRestOfDocument(reader);
       //List<Student> students = new ArrayList<>();
       //Student student = null;
       //String text = "";
       boolean flag=true;
       while (reader.hasNext()) {
      	 int type = reader.next();
      	 switch (type) {
      	 case XMLStreamConstants.START_ELEMENT:
      		 //System.out.println(reader.getLocalName());//getLocalName()为不包含命名空间名的元素名称
      		 if (reader.getNamespaceURI().trim().length() != 0) {
      			 String prefix = reader.getPrefix();//返回当前事件的前缀，如果事件没有前缀则返回 null
      			 if (prefix == null) {
      				 prefix = "[None]";
      			 }
      			 if (flag) {
      				 System.out.print("\n"+prefix +":"+reader.getLocalName()+" xmlns:"+prefix+"=\""+ reader.getNamespaceURI()+"\"");
      				 flag=false;
      				 }
      			 else {
      				 System.out.print("\n"+prefix +":"+reader.getLocalName());
      				 
      			 }
      		 }

      		 if (reader.getAttributeCount() > 0) {
      			 for (int i = 0; i < reader.getAttributeCount(); i++) {
      				 //System.out.println("Attribute:"+ reader.getAttributeLocalName(i) + "=\"" + reader.getAttributeValue(i)+"\"");
      				 System.out.print(" "+ reader.getAttributeLocalName(i) + "=\"" + reader.getAttributeValue(i)+"\"");
      				 //System.out.print(" " + attr.getName() + "=\"" + attr.getValue() + "\"");
      				 String attURI = reader.getAttributeNamespace(i);
      				 if (attURI.trim().length() != 0) {
      					 String attPrefix = reader.getAttributePrefix(i);
      					 if (attPrefix == null || attPrefix.equals("")) {
      						 attPrefix = "[None]";
      					 }
      					 //System.out.println("prefix=" + attPrefix + ",URI=" + attURI);
      					 System.out.print("\n"+attPrefix +":"+reader.getLocalName());
      				 }
      			 }
      			 //System.out.println();
      			 
      		 }
      		 break;
      	 case XMLStreamConstants.END_ELEMENT:
      		 System.out.print("\nXMLStreamConstants.END_ELEMENT");
      		 break;
      	 case XMLStreamConstants.CHARACTERS:
      		 if (!reader.isWhiteSpace()) {
      			 System.out.print("\nCD:" + reader.getText());
      		 }
      		 break;
      	 case XMLStreamConstants.DTD:
      		 System.out.print("\nDTD:" + reader.getText());
      		 break;
      	 case XMLStreamConstants.SPACE:
      		 System.out.print("\n ");
      		 break;
      	 case XMLStreamConstants.COMMENT:
      		 System.out.print("\ncomment: "+reader.getText());
      		 break;
      	 default:
      		 System.out.print("\n"+type);
      	 }
       }
    }
    
    /**
     * 生成xml
     * @throws Exception
     */
    @Test
    public void toXml() throws Exception {
   	 System.out.println("\ntoXML----------");
        XMLOutputFactory factory = XMLOutputFactory.newInstance();
        XMLStreamWriter writer = factory.createXMLStreamWriter(System.out);
        writer.writeStartDocument("UTF-8", "1.0");
        writer.writeStartElement("school", "class", "http://www.w3.org/TR/html4/school/");

        //第一个学生
        writer.writeStartElement("school", "student", "http://www.w3.org/TR/html4/school/");
        writer.writeAttribute("rollno", "1");
        writer.writeAttribute("school","http://www.w3.org/TR/html4/school/", "age", "10");
        writer.writeStartElement("school", "firstname", "http://www.w3.org/TR/html4/school/");
        writer.writeCharacters("cxx1");
        writer.writeEndElement();
        writer.writeStartElement("lastname");
        writer.writeCharacters("Bob1");
        writer.writeEndElement();
        writer.writeStartElement("nickname");
        writer.writeCharacters("stars1");
        writer.writeEndElement();
        writer.writeStartElement("marks");
        writer.writeCharacters("85");
        writer.writeEndElement();
        writer.writeEndElement();

        //第二个学生
        writer.writeStartElement("student");
        writer.writeAttribute("rollno", "2");
        writer.writeStartElement("firstname");
        writer.writeCharacters("cxx2");
        writer.writeEndElement();
        writer.writeStartElement("lastname");
        writer.writeCharacters("Bob2");
        writer.writeEndElement();
        writer.writeStartElement("nickname");
        writer.writeCharacters("stars2");
        writer.writeEndElement();
        writer.writeStartElement("marks");
        writer.writeCharacters("85");
        writer.writeEndElement();
        writer.writeEndElement();

        //第三个学生
        writer.writeStartElement("student");
        writer.writeAttribute("rollno", "3");
        writer.writeStartElement("firstname");
        writer.writeCharacters("cxx3");
        writer.writeEndElement();
        writer.writeStartElement("lastname");
        writer.writeCharacters("Bob3");
        writer.writeEndElement();
        writer.writeStartElement("nickname");
        writer.writeCharacters("stars3");
        writer.writeEndElement();
        writer.writeStartElement("marks");
        writer.writeCharacters("85");
        writer.writeEndElement();
        writer.writeEndElement();

        writer.writeEndElement();
        writer.writeEndDocument();
    }
}
